home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / gcc / ixemulsrc.lha / ixemul-41.4 / library / select.c < prev    next >
C/C++ Source or Header  |  1995-05-28  |  8KB  |  269 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  select.c,v 1.1.1.1 1994/04/04 04:30:33 amiga Exp
  20.  *
  21.  *  select.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:33  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.2  1993/11/05  22:00:59  mwild
  26.  *  extensively rewritten to work better along with inet.library
  27.  *
  28.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  29.  *  Initial revision
  30.  *
  31.  */
  32.  
  33. #define KERNEL
  34. #include "ixemul.h"
  35. #include "kprintf.h"
  36.  
  37. #include <sys/time.h>
  38.  
  39. #include "select.h"
  40.  
  41. #define __time_req (p->u_time_req)
  42. #define __tport    (p->u_sync_mp)
  43.  
  44. static void inline setcopy(int nfd, u_int *ifd, u_int *ofd)
  45. {
  46.   /* this procedure is here, because it's "normal" that if you only
  47.    * want to select on fd 0,1,2 eg. you only pass a long to select,
  48.    * not a whole fd_set, so we can't simply copy over results in the
  49.    * full size of an fd_set.. */
  50.   
  51.   /* we have to copy that many longs... */
  52.   nfd = (nfd+31) >> 5;
  53.   while (nfd--) *ofd++ = *ifd++;
  54. }
  55.  
  56. int
  57. select(int nfd, fd_set *ifd, fd_set *ofd, fd_set *efd, struct timeval *timeout)
  58. {
  59.   struct file *f;
  60.   int i, waitin, waitout, waitexc, dotout;
  61.   int result, ostat;
  62.   u_int wait_sigs;
  63.   struct timeval end_time;
  64.   int skipped_wait;
  65.   struct user *p = &u;
  66.   u_long recv_wait_sigs = 0;
  67.  
  68.   /* as long as I don't support anything similar to a network, I surely
  69.    * won't get any exceptional conditions, so *efd is mapped into 
  70.    * *ifd, if it's set. */
  71.    
  72.   /* first check, that all included descriptors are valid and support
  73.    * the requested operation. If the user included a request to wait
  74.    * for a descriptor to be ready to read, while the descriptor was only
  75.    * opened for writing, the requested bit is immediately cleared
  76.    */
  77.   waitin = waitout = waitexc = 0;
  78.   if (nfd > NOFILE) nfd = NOFILE;
  79.  
  80.   for (i = 0; i < nfd; i++)
  81.     {
  82.       if (ifd && FD_ISSET(i, ifd) && (f = p->u_ofile[i]))
  83.     {
  84.       if (!f->f_read || !f->f_select)
  85.         FD_CLR(i, ifd);
  86.       else
  87.         ++waitin;
  88.     }
  89.       if (ofd && FD_ISSET(i, ofd) && (f = p->u_ofile[i]))
  90.     {
  91.       if (!f->f_write || !f->f_select)
  92.         FD_CLR(i, ofd);
  93.       else
  94.         ++waitout;
  95.     }
  96.       if (efd && FD_ISSET(i, efd) && (f = p->u_ofile[i]))
  97.     {
  98.       /* question: can an exceptional condition also occur on a 
  99.        * write-only fd?? */
  100.       if (!f->f_read || !f->f_select)
  101.         FD_CLR(i, efd);
  102.       else
  103.         ++waitexc;
  104.     }
  105.     }
  106.  
  107.   if (0)
  108.     {
  109.       /* this belongs logically here, not at the end of the function */
  110. badfd:
  111.       errno = EBADF;
  112.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  113.       return -1;
  114.     }
  115.  
  116.  
  117.   /* now, if we see, that we're not waiting for anything, AND if
  118.    * timeout is NULL (not 0 seconds!), than select() is just something
  119.    * like a very complex pause() call ;-)) */
  120.   if (waitin + waitout + waitexc == 0 && !timeout)
  121.     return syscall (SYS_pause);
  122.  
  123.   if (dotout=(timeout && timerisset(timeout)))
  124.     {
  125.       /* remember the time we have to leave (timeout) */
  126.       gettimeofday (&end_time, 0);
  127.       end_time.tv_usec += timeout->tv_usec;
  128.       /* this conversion should be cheaper than a division and a modulo.. */
  129.       while (end_time.tv_usec >= 1000000)
  130.         {
  131.       end_time.tv_usec -= 1000000;
  132.       end_time.tv_sec++;
  133.     }
  134.       end_time.tv_sec += timeout->tv_sec;
  135.     }
  136.  
  137.   /* have to make sure we can clean up the timer-request ! */
  138.   ostat = p->p_stat;
  139.   p->p_stat = SSLEEP;
  140.   p->p_wchan = (caddr_t) select; /* will once be an own variable */
  141.   p->p_wmesg = "select";
  142.  
  143.  
  144.   for (skipped_wait = 0; ; skipped_wait=1)
  145.     {
  146.       fd_set readyin, readyout, readyexc;
  147.       int tout, readydesc, cmd;
  148.  
  149.       FD_ZERO(&readyin);
  150.       FD_ZERO(&readyout);
  151.       FD_ZERO(&readyexc);
  152.  
  153.       tout = 
  154.         readydesc = 0;
  155.  
  156.       /* have to always wait for the `traditional' ^C and the library internal
  157.        * sleep_sig as well */
  158.       wait_sigs = SIGBREAKF_CTRL_C | (1 << p->u_sleep_sig);
  159.  
  160.       if (/*(dotout || !timeout) &&*/ skipped_wait)
  161.     {
  162.       cmd = SELCMD_CHECK;
  163.  
  164.       /* have all watched files get prepared for selecting */
  165.           for (i = 0; i < nfd; i++)
  166.         {
  167.           if (ifd && FD_ISSET (i, ifd) && (f = p->u_ofile[i]))
  168.             wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_IN);
  169.           if (ofd && FD_ISSET (i, ofd) && (f = p->u_ofile[i]))
  170.             wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_OUT);
  171.           if (efd && FD_ISSET (i, efd) && (f = p->u_ofile[i]))
  172.             wait_sigs |= f->f_select (f, SELCMD_PREPARE, SELMODE_EXC);
  173.         }
  174.  
  175.       /* note: we never post a timeout request of less than SELTIMEOUT, so
  176.            * select() precision depends on SELTIMEOUT. However, considering that
  177.            * this call emulates a Unix syscall, this comes quite near to Unix
  178.            * precision, if not better ;-)) */
  179.       __time_req->tr_time.tv_sec = 0;
  180.       __time_req->tr_time.tv_usec = SELTIMEOUT;
  181.           __time_req->tr_node.io_Command = TR_ADDREQUEST;
  182.           SendIO((struct IORequest *)__time_req);
  183.           /* clear the bit, it's used for sync packets too, and might be set */
  184.           SetSignal (0, 1 << __tport->mp_SigBit);
  185.       wait_sigs |= 1 << __tport->mp_SigBit;
  186.  
  187.           /* now wait for all legally possible signals, this includes BSD
  188.            * signals (but want at least one signal set!) */
  189.           while (! (recv_wait_sigs = Wait (wait_sigs))) ;
  190.  
  191.       /* IMPORTANT: unqueue the timer request BEFORE polling the fd's,
  192.        *            or __wait_packet() will treat the timer request
  193.        *            as a packet... */
  194.  
  195.       if (! CheckIO ((struct IORequest *)__time_req))
  196.             AbortIO ((struct IORequest *)__time_req);
  197.           WaitIO ((struct IORequest *)__time_req);
  198.         }
  199.       else
  200.     cmd = SELCMD_POLL;
  201.  
  202.       /* no matter what caused Wait() to return, wait for all requests to
  203.        * complete (we CAN'T abort a DOS packet, sigh..) */
  204.  
  205.       /* collect information from the file descriptors */
  206.       for (i = 0; i < nfd; i++)
  207.     {
  208.       if (ifd && FD_ISSET (i, ifd) && (f = p->u_ofile[i])
  209.           && f->f_select (f, cmd, SELMODE_IN))
  210.         {
  211.           FD_SET (i, &readyin);
  212.           ++ readydesc;
  213.         }
  214.       if (ofd && FD_ISSET (i, ofd) && (f = p->u_ofile[i])
  215.           && f->f_select (f, cmd, SELMODE_OUT))
  216.         {
  217.           FD_SET (i, &readyout);
  218.           ++ readydesc;
  219.         }
  220.       if (efd && FD_ISSET (i, efd) && (f = p->u_ofile[i])
  221.               && f->f_select (f, cmd, SELMODE_EXC))
  222.         {
  223.           FD_SET (i, &readyexc);
  224.           ++ readydesc;
  225.         }
  226.     }
  227.  
  228.       /* we have a timeout condition, if readydesc == 0, dotout == 1 and 
  229.        * end_time < current time */
  230.       if (!readydesc && dotout)
  231.         {
  232.           struct timeval current_time;
  233.           
  234.           gettimeofday (¤t_time, 0);
  235.           tout = timercmp (&end_time, ¤t_time, <);
  236.     }
  237.  
  238.       if (readydesc || tout || (timeout && !timerisset(timeout)))
  239.     {
  240.       if (ifd) setcopy(nfd, (u_int *)&readyin,  (u_int *)ifd);
  241.       if (ofd) setcopy(nfd, (u_int *)&readyout, (u_int *)ofd);
  242.       if (efd) setcopy(nfd, (u_int *)&readyexc, (u_int *)efd);
  243.       result = readydesc; /* ok for tout, since then readydesc is already 0 */
  244.       break;
  245.     }
  246.  
  247.       if (recv_wait_sigs & (SIGBREAKF_CTRL_C | (1 << p->u_sleep_sig)))
  248.         {
  249.           result = -1;
  250.           break;
  251.         }
  252.     }
  253.  
  254.   p->p_wchan = 0;
  255.   p->p_wmesg = 0;
  256.   p->p_stat = ostat;
  257.   /* need special processing for ^C here, as that is completely disabled
  258.      when we're SSLEEPing */
  259.   if (recv_wait_sigs & SIGBREAKF_CTRL_C)
  260.     _psignal (FindTask (0), SIGINT);
  261.   setrun (FindTask (0));
  262.  
  263.   if (result == -1)
  264.     /* have to set this here, since errno can be changed in signal handlers */
  265.     *(p->u_errno) = EINTR;
  266.  
  267.   return result;
  268. }
  269.